libobs_simple\sources\windows\sources/
window_capture.rs1use crate::{
2 define_object_manager,
3 sources::{
4 macro_helper::impl_custom_source,
5 windows::{ObsHookableSourceSignals, ObsHookableSourceTrait},
6 },
7};
8
9use super::{ObsWindowCaptureMethod, ObsWindowPriority};
10use crate::error::ObsSimpleError;
11use libobs_simple_macro::obs_object_impl;
12#[cfg(feature = "window-list")]
13use libobs_window_helper::{get_all_windows, WindowInfo, WindowSearchMode};
14use libobs_wrapper::{
15 data::{ObsObjectBuilder, ObsObjectUpdater},
16 scenes::{ObsSceneItemRef, ObsSceneRef, SceneItemExtSceneTrait},
17 sources::{ObsSourceBuilder, ObsSourceRef},
18 utils::ObsError,
19};
20use num_traits::ToPrimitive;
21
22define_object_manager!(
23 #[derive(Debug)]
25 struct WindowCaptureSource("window_capture", *mut libobs::obs_source) for ObsSourceRef {
26
27 #[obs_property(type_t = "enum")]
38 priority: ObsWindowPriority,
39
40 #[obs_property(type_t = "string", settings_key = "window")]
50 window_raw: String,
51
52 #[obs_property(type_t = "bool")]
53 cursor: bool,
55
56 capture_audio: bool,
60
61 #[obs_property(type_t = "bool")]
62 force_sdr: bool,
64
65 #[obs_property(type_t = "bool")]
66 client_area: bool,
68
69 #[obs_property(type_t = "bool")]
70 compatibility: bool,
71
72 capture_method: Option<ObsWindowCaptureMethod>,
73});
74
75#[cfg(feature = "window-list")]
76#[libobs_simple_macro::obs_object_impl]
77impl WindowCaptureSource {
78 pub fn get_windows(
80 mode: WindowSearchMode,
81 ) -> Result<Vec<libobs_wrapper::unsafe_send::Sendable<WindowInfo>>, ObsSimpleError> {
82 Ok(get_all_windows(mode)
83 .map_err(ObsSimpleError::WindowHelperError)?
84 .into_iter()
85 .map(libobs_wrapper::unsafe_send::Sendable)
86 .collect())
87 }
88
89 pub fn set_window(self, window: &libobs_wrapper::unsafe_send::Sendable<WindowInfo>) -> Self {
99 self.set_window_raw(window.0.obs_id.as_str())
100 }
101}
102
103impl<'a> WindowCaptureSourceUpdater<'a> {
104 pub fn set_capture_method(mut self, method: ObsWindowCaptureMethod) -> Self {
105 self.get_settings_updater()
106 .set_int_ref("method", method.to_i32().unwrap() as i64);
107
108 self
109 }
110}
111
112impl WindowCaptureSourceBuilder {
113 pub fn set_capture_method(mut self, method: ObsWindowCaptureMethod) -> Self {
115 self.capture_method = Some(method);
116 self
117 }
118}
119
120#[obs_object_impl]
121impl WindowCaptureSource {
122 pub fn set_capture_audio(mut self, capture_audio: bool) -> Result<Self, ObsSimpleError> {
123 use crate::sources::windows::audio_capture_available;
124
125 if capture_audio && !audio_capture_available(self.runtime())? {
126 return Err(ObsSimpleError::FeatureNotAvailable(
127 "Game Audio Capture is not available on this system",
128 ));
129 }
130
131 self.get_settings_updater()
132 .set_bool_ref("capture_audio", capture_audio);
133
134 Ok(self)
135 }
136}
137
138impl_custom_source!(
139 WindowCaptureSource,
140 ObsHookableSourceSignals,
141 NO_SPECIFIC_SIGNALS_FUNCTION
142);
143
144impl ObsHookableSourceTrait for WindowCaptureSource {
145 fn source_specific_signals(&self) -> std::sync::Arc<ObsHookableSourceSignals> {
146 self.source_specific_signals.clone()
147 }
148}
149
150impl ObsSourceBuilder for WindowCaptureSourceBuilder {
151 type T = WindowCaptureSource;
152
153 fn build(self) -> Result<Self::T, ObsError> {
154 let runtime = self.runtime.clone();
155
156 let b = self.object_build()?;
157
158 let source = ObsSourceRef::new_from_info(b, runtime)?;
159 WindowCaptureSource::new(source)
160 }
161
162 fn add_to_scene(mut self, scene: &mut ObsSceneRef) -> Result<ObsSceneItemRef<Self::T>, ObsError>
163 where
164 Self: Sized,
165 {
166 self.get_settings_updater().set_int_ref(
168 "method",
169 ObsWindowCaptureMethod::MethodAuto.to_i32().unwrap() as i64,
170 );
171
172 let method_to_set = self.capture_method;
173 let mut source = self.build()?;
174 let scene_item = scene.add_source(source.clone())?;
175
176 if let Some(method) = method_to_set {
177 source
178 .create_updater()?
179 .set_capture_method(method)
180 .update()?;
181 }
182
183 Ok(scene_item)
184 }
185}